/***********************************************************************
 * Module:  ResizeCommand.java
 * Author:  Nikola
 * Purpose: Defines the Class ResizeCommand
 ***********************************************************************/

package genedit.controller;

import java.awt.geom.Point2D;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import genedit.model.graph.ConnectionPoint;
import genedit.model.graph.GraphElement;
import genedit.model.graph.Link;
import genedit.view.graph.ElementPainter;
import genedit.view.graph.LinkPainter;
import genedit.view.graph.SelectionHandleHandler.Handle;

public class ResizeCommand extends Command {
	private double moveByX = 0;
	private double moveByY = 0;
	private double globalDiffX=0;
	private double globalDiffY=0;
	private Handle handle;
	private HashMap<GraphElement,HashMap<ConnectionPoint,Point2D>> connectionPointsBackup;
	public static HashMap<GraphElement,HashMap<ConnectionPoint,Point2D>> translateConnectionPoints=null;
	private Set<GraphElement> resizedElements;
	private boolean useGlobal;

	/** @param isUndoable */
	public ResizeCommand(boolean isUndoable,double diffX,double diffY, Handle handle) {
		super(isUndoable);
		globalDiffX=diffX;
		globalDiffY=diffY;
		this.handle = handle;
		this.useGlobal=false;
	}

	public void execute() {
		if(!useGlobal&&translateConnectionPoints==null){
			//bacukp points
			translateConnectionPoints=new HashMap<GraphElement, HashMap<ConnectionPoint,Point2D>>();
			for(GraphElement element:resizedElements){
				HashMap<ConnectionPoint,Point2D> points=new HashMap<ConnectionPoint, Point2D>();
				for(ConnectionPoint point:element.getConnectionPoints()){
					points.put(point, new Point2D.Double(point.getPosition().getX(),point.getPosition().getY()));
				}
				translateConnectionPoints.put(element, points);
			}
		}
		
		Iterator<GraphElement> iterator = getIteratorResizedElements();
		while (iterator.hasNext()) {
			GraphElement current = iterator.next();
			//ne primenjivati na link
			if(current instanceof Link) {
				continue;
			}
			Point2D elementPosition = current.getPosition();
			if(current.getSize().getWidth() + moveByX>10 && current.getSize().getHeight() + moveByY>10) {
				switch (handle) {
					case North:
						elementPosition.setLocation(elementPosition.getX() - moveByX, elementPosition.getY() - moveByY);
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);					
						break;
					case South:
						elementPosition.setLocation(elementPosition.getX(), elementPosition.getY());
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);				
						break;
					case East:
						elementPosition.setLocation(elementPosition.getX(), elementPosition.getY());
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);
						break;
					case West:
						elementPosition.setLocation(elementPosition.getX() - moveByX, elementPosition.getY() - moveByY);
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);
						break;
					case SouthEast:
						elementPosition.setLocation(elementPosition.getX(), elementPosition.getY());
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);
						break;
					case NorthWest:
						elementPosition.setLocation(elementPosition.getX() - moveByX, elementPosition.getY() - moveByY);
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);
						break;
					case SouthWest:
						elementPosition.setLocation(elementPosition.getX() - moveByX, elementPosition.getY());
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);
						break;
					case NorthEast:
						elementPosition.setLocation(elementPosition.getX(), elementPosition.getY() - moveByY);
						current.getSize().setSize(current.getSize().getWidth() + moveByX, current.getSize().getHeight() + moveByY);
						break;
					default:
						break;
				}
				
				/*
				for (ConnectionPoint cp : current.getConnectionPoints()){
					double y = cp.getResizeFactorY()*current.getSize().getHeight();
					double x = cp.getResizeFactorX()*current.getSize().getWidth();
					cp.getPosition().setLocation(elementPosition.getX()+x, elementPosition.getY() + y);
				}
				*/
				
				ElementPainter currentPainter=getDocument().getPainter(current);
				currentPainter.resizeShape();
				currentPainter.refreshAffine();
			
				for (ConnectionPoint cp : current.getConnectionPoints()){
					for(Link link1 : cp.getEnding()) {
						if(!resizedElements.contains(getDocument().getPainter(link1))){
						link1.removeIntersectPoints();
						link1.addIntersectionPoints();
						}
					}
					for(Link link1 : cp.getStarting()) {
						if(!resizedElements.contains(getDocument().getPainter(link1))){
						link1.removeIntersectPoints();
						link1.addIntersectionPoints();
						}
					}
				}
			}
		} 
		
		iterator = getIteratorResizedElements();
		// vratimo connection pointe unutar elemenata
		while (iterator.hasNext()) { 
			GraphElement current = iterator.next();
			if (!(current instanceof Link)) {
				ElementPainter currentPainter=getDocument().getPainter(current);
				for (ConnectionPoint cp : current.getConnectionPoints()){
					if(!currentPainter.isElementAt(cp.getPosition())){
						Point2D newPosition=new Point2D.Double(current.getPosition().getX()+current.getSize().getWidth()/2,
								current.getPosition().getY()+current.getSize().getHeight()/2);
						cp.setPosition(newPosition);
					}
				}
			}
		}
		
		iterator = getIteratorResizedElements();
		// ispravi likove
		while (iterator.hasNext()) { 
			GraphElement current = iterator.next();
			if (!(current instanceof Link)) {
				for (ConnectionPoint cp : current.getConnectionPoints()){
					for(Link link1 : cp.getEnding()) {
						if(!resizedElements.contains(getDocument().getPainter(link1))){
							link1.removeIntersectPoints();
							link1.addIntersectionPoints();
						}
					}
					for(Link link1 : cp.getStarting()) {
						if(!resizedElements.contains(getDocument().getPainter(link1))){
							link1.removeIntersectPoints();
							link1.addIntersectionPoints();
						}
					}
				}
			}
		}
		
		getDocument().getModel().refresh();
		
		//ako je kraj izrade veze
		if(undoable){
			if(!useGlobal){
				connectionPointsBackup=translateConnectionPoints;
			}
			translateConnectionPoints=null;
			for(GraphElement element : resizedElements){
				if(!(element instanceof Link)) {
					for(ConnectionPoint point:element.getConnectionPoints()){
						for(Link link:point.getStarting()){
							link.removeIntersectPoints();
							link.rectLink();
							link.addIntersectionPoints();
						}
						for(Link link:point.getEnding()){
							link.removeIntersectPoints();
							link.rectLink();
							link.addIntersectionPoints();
						}
					}
				}
			}
		}
	}

	public void undo() {
		useGlobal=true;
		moveByX=globalDiffX;
		moveByY=globalDiffY;
		
		Iterator<GraphElement> iterator = getIteratorResizedElements();
		while (iterator.hasNext()) {
			GraphElement current = iterator.next();
			if(current instanceof Link) { 
				continue;
			}
			Point2D elementPosition = current.getPosition();
			if(current.getSize().getWidth() + globalDiffX>10 && current.getSize().getHeight() + globalDiffY>10) {
				switch (handle) {
				case North:
					elementPosition.setLocation(elementPosition.getX() + globalDiffX, elementPosition.getY() + globalDiffY);
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);					
					break;
				case South:
					elementPosition.setLocation(elementPosition.getX(), elementPosition.getY());
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);				
					break;
				case East:
					elementPosition.setLocation(elementPosition.getX(), elementPosition.getY());
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);
					break;
				case West:
					elementPosition.setLocation(elementPosition.getX() + globalDiffX, elementPosition.getY() + globalDiffY);
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);
					break;
				case SouthEast:
					elementPosition.setLocation(elementPosition.getX(), elementPosition.getY());
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);
					break;
				case NorthWest:
					elementPosition.setLocation(elementPosition.getX() + globalDiffX, elementPosition.getY() + globalDiffY);
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);
					break;
				case SouthWest:
					elementPosition.setLocation(elementPosition.getX() + globalDiffX, elementPosition.getY());
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);
					break;
				case NorthEast:
					elementPosition.setLocation(elementPosition.getX(), elementPosition.getY() + globalDiffY);
					current.getSize().setSize(current.getSize().getWidth() - globalDiffX, current.getSize().getHeight() - globalDiffY);
					break;
				default:
					break;
				}
				
				for (ConnectionPoint cp : current.getConnectionPoints()){
					double y = cp.getResizeFactorY()*current.getSize().getHeight();
					double x = cp.getResizeFactorX()*current.getSize().getWidth();
					cp.getPosition().setLocation(elementPosition.getX()+x, elementPosition.getY() + y);
				}
				
				ElementPainter currentPainter=getDocument().getPainter(current);
				currentPainter.resizeShape();
				currentPainter.refreshAffine();
				/*
				for (ConnectionPoint cp : current.getConnectionPoints()){
					for(Link link1 : cp.getEnding()) {
						if(!resizedElements.contains(getDocument().getPainter(link1))){
							link1.removeIntersectPoints();
							link1.addIntersectionPoints();
						}
					}
					for(Link link1 : cp.getStarting()) {
						if(!resizedElements.contains(getDocument().getPainter(link1))){
						link1.removeIntersectPoints();
						link1.addIntersectionPoints();
						}
					}
				}
				*/
				
				getDocument().getModel().refresh();

			}
		}
		
		//vraćanje starih veza
		for(GraphElement element:resizedElements){
			HashMap<ConnectionPoint,Point2D> points=connectionPointsBackup.get(element);
			for(ConnectionPoint point:element.getConnectionPoints()){
				Point2D oldPosition=points.get(point);
				point.setPosition(new Point2D.Double(oldPosition.getX(),oldPosition.getY()));
			}
		}
		
		for(GraphElement element : resizedElements){
			if(!(element instanceof Link)) {
				for(ConnectionPoint point:element.getConnectionPoints()){
					for(Link link:point.getStarting()){
						link.removeIntersectPoints();
						link.rectLink();
						link.addIntersectionPoints();
					}
					for(Link link:point.getEnding()){
						link.removeIntersectPoints();
						link.rectLink();
						link.addIntersectionPoints();
					}
				}
			}
		}
	}
	

	public double getMoveByX() {
		return moveByX;
	}


	/** @param newMoveByX */
	public void setMoveByX(double newMoveByX) {
		moveByX = newMoveByX;
	}

	public double getMoveByY() {
		return moveByY;
	}

	
	/** @param newMoveByY */
	public void setMoveByY(double newMoveByY) {
		moveByY = newMoveByY;
	}

	/** @pdGenerated default getter */
	public Set<GraphElement> getResizedElements() {
		if (resizedElements == null)
			resizedElements = new java.util.HashSet<GraphElement>();
		return resizedElements;
	}

	/** @pdGenerated default iterator getter */
	public java.util.Iterator<GraphElement> getIteratorResizedElements() {
		if (resizedElements == null)
			resizedElements = new java.util.HashSet<GraphElement>();
		return resizedElements.iterator();
	}

	/**
	 * @pdGenerated default setter
	 * @param newMovedElements
	 */
	public void setResizedElements(
			java.util.Collection<GraphElement> newMovedElements) {
		removeAllResizedElements();
		for (java.util.Iterator<GraphElement> iter = newMovedElements
				.iterator(); iter.hasNext();)
			addResizedElements((GraphElement) iter.next());
	}

	/**
	 * @pdGenerated default add
	 * @param newElementPainter
	 */
	public void addResizedElements(GraphElement newElementPainter) {
		if (newElementPainter == null)
			return;
		if (this.resizedElements == null)
			this.resizedElements = new java.util.HashSet<GraphElement>();
		if (!this.resizedElements.contains(newElementPainter))
			this.resizedElements.add(newElementPainter);
	}

	/**
	 * @pdGenerated default remove
	 * @param oldElementPainter
	 */
	public void removeResizedElements(GraphElement oldElementPainter) {
		if (oldElementPainter == null)
			return;
		if (this.resizedElements != null)
			if (this.resizedElements.contains(oldElementPainter))
				this.resizedElements.remove(oldElementPainter);
	}

	/** @pdGenerated default removeAll */
	public void removeAllResizedElements() {
		if (resizedElements != null)
			resizedElements.clear();
	}

}